package com.sunwayworld.basemodule.samplemanage.location.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.sunwayworld.basemodule.common.constant.LimsConstant;
import com.sunwayworld.basemodule.common.utils.LimsTreeHelper;
import com.sunwayworld.basemodule.samplemanage.location.bean.*;
import com.sunwayworld.basemodule.samplemanage.location.dao.LimsLocationDao;
import com.sunwayworld.basemodule.samplemanage.location.service.LimsLocationBoardHoleService;
import com.sunwayworld.basemodule.samplemanage.location.service.LimsLocationBoardService;
import com.sunwayworld.basemodule.samplemanage.location.service.LimsLocationService;
import com.sunwayworld.basemodule.samplemanage.location.validators.LimsLocationDeleteValidator;
import com.sunwayworld.framework.at.annotation.AuditTrailEntry;
import com.sunwayworld.framework.at.annotation.AuditTrailType;
import com.sunwayworld.framework.context.ApplicationContextHelper;
import com.sunwayworld.framework.context.LocalContextHelper;
import com.sunwayworld.framework.context.concurrent.GikamConcurrentLocker;
import com.sunwayworld.framework.database.sql.Order;
import com.sunwayworld.framework.exception.InvalidDataException;
import com.sunwayworld.framework.i18n.I18nHelper;
import com.sunwayworld.framework.mybatis.mapper.MapperParameter;
import com.sunwayworld.framework.mybatis.mapper.MatchPattern;
import com.sunwayworld.framework.mybatis.mapper.SearchFilter;
import com.sunwayworld.framework.restful.data.RestJsonWrapperBean;
import com.sunwayworld.framework.spring.annotation.GikamBean;
import com.sunwayworld.framework.support.PersistableHelper;
import com.sunwayworld.framework.support.tree.TreeDescriptor;
import com.sunwayworld.framework.support.tree.TreeHelper;
import com.sunwayworld.framework.utils.*;
import com.sunwayworld.framework.validator.data.annotation.ValidateDataWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Repository
@GikamBean
public class LimsLocationServiceImpl implements LimsLocationService {

    private static final Logger log = LoggerFactory.getLogger(LimsLocationServiceImpl.class);

    private static final Integer QUERY_MAX_QUANTITY = 10000;

    private static final Integer QUERY_TIMES = 10;

    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(QUERY_TIMES);

    private final static String LIMS_LOCATION_ID = "LIMS_LOCATION_ID";

    @Autowired
    private LimsLocationDao limsLocationDao;

    @Autowired
    private LimsLocationBoardService boardService;

    @Autowired
    @Lazy
    private LimsLocationBoardHoleService locationBoardHoleService;

    @Override
    @SuppressWarnings("unchecked")
    public LimsLocationDao getDao() {
        return limsLocationDao;
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.INSERT)
    public Long insert(RestJsonWrapperBean jsonWrapper) {
        LimsLocationBean locationBean = jsonWrapper.parseUnique(LimsLocationBean.class);
        locationBean.setId(ApplicationContextHelper.getNextIdentity());
        locationBean.setLocationDesc(locationBean.getStorageCode());
        locationBean.setLevel("1");
        locationBean.setGroup(String.valueOf(locationBean.getId()));
        int firstSorter = Integer.parseInt(getDao().selectMaxSorterByParam(new MapperParameter(){{setFilter(SearchFilter.instance().match("level",LimsConstant.LEVEL_FIRST).filter(MatchPattern.EQ)
                .match("storage",locationBean.getStorage()).filter(MatchPattern.EQ)
                .match("storageType",locationBean.getStorageType()).filter(MatchPattern.EQ));}}));
        if ("液氮罐".equals(locationBean.getStorageType())){
            locationBean.setLocationNo("Y" + String.format("%04d",firstSorter));
        }else{
            locationBean.setLocationNo("B" + String.format("%04d",firstSorter));
        }
        locationBean.setStorageName(locationBean.getLocationNo());
        locationBean.setSorter(firstSorter);
        locationBean.setParentId(1L);
        List<LimsLocationBean> locationList = new ArrayList<>();
        locationList.add(locationBean);
        int cs = !StringUtils.isEmpty(locationBean.getExt$().get(LimsConstant.CS))?NumberUtils.parseInt(locationBean.getExt$().get(LimsConstant.CS)):0;// 层数
        int jzs = !StringUtils.isEmpty(locationBean.getExt$().get(LimsConstant.JZS))?NumberUtils.parseInt(locationBean.getExt$().get(LimsConstant.JZS)):0;// 架子数
        int hzs = !StringUtils.isEmpty(locationBean.getExt$().get(LimsConstant.HZS))?NumberUtils.parseInt(locationBean.getExt$().get(LimsConstant.HZS)):0;// 盒子数
        int locationSize = cs + cs * jzs + cs * jzs * hzs;
        List<Long> locationIdList = ApplicationContextHelper.getNextIdentityList(locationSize);
        int index = 0;
        // 层
        int thirdIndex = 1;
        int fourIndex = 1;
        for (int c = 1; c <= cs; c++) {
            LimsLocationBean lsilocationbeancs = new LimsLocationBean();
            lsilocationbeancs.setId(locationIdList.get(index++));
            lsilocationbeancs.setStorage(locationBean.getStorage());
            lsilocationbeancs.setStorageType(locationBean.getStorageType());
            lsilocationbeancs.setStorageCode("F" + c);// 层名
            lsilocationbeancs.setSorter(c);
            lsilocationbeancs.setLevel(LimsConstant.LEVEL_SECEND);
            lsilocationbeancs.setLayerCode(lsilocationbeancs.getId().toString());
            lsilocationbeancs.setParentId(locationBean.getId());
            lsilocationbeancs.setGroup(String.valueOf(locationBean.getId()));
            if ("液氮罐".equals(locationBean.getStorageType())){
                lsilocationbeancs.setStorageName("Q" + String.format("%04d", c));
            }else{
                lsilocationbeancs.setStorageName("J" + String.format("%04d", c));
            }
            lsilocationbeancs.setLocationNo(locationBean.getLocationNo() + "-" + lsilocationbeancs.getStorageName());
            lsilocationbeancs.setLocationDesc("F" + c);
            locationList.add(lsilocationbeancs);
            // 架子
            for (int j = 1; j <= jzs; j++) {
                LimsLocationBean locationBean2 = new LimsLocationBean();
                locationBean2.setId(locationIdList.get(index++));
                locationBean2.setStorage(locationBean.getStorage());
                locationBean2.setParentId(lsilocationbeancs.getId());
                locationBean2.setGroup(String.valueOf(locationBean.getId()));
                locationBean2.setLayerCode(lsilocationbeancs.getLayerCode());
                locationBean2.setStorageName("T" + String.format("%04d", thirdIndex));
                locationBean2.setLocationNo(lsilocationbeancs.getLocationNo() + "-" + locationBean2.getStorageName());
                locationBean2.setLocationDesc("J" + thirdIndex);
                locationBean2.setStorageCode("J" + thirdIndex);
                locationBean2.setStorageType(locationBean.getStorageType());
                locationBean2.setLevel(LimsConstant.LEVEL_THIRD);
                locationBean2.setColumnNum(1);
                locationBean2.setRowNum(thirdIndex);
                locationBean2.setColNum(1);
                locationBean2.setSorter(j);
                locationList.add(locationBean2);
                thirdIndex++;
                // 盒子
                for (int k = 1; k <= hzs; k++) {
                    LimsLocationBean locationBean3 = new LimsLocationBean();
                    locationBean3.setId(locationIdList.get(index++));
                    locationBean3.setParentId(locationBean2.getId());
                    locationBean3.setGroup(String.valueOf(locationBean.getId()));
                    locationBean3.setSorter(k);
                    locationBean3.setStorage(locationBean.getStorage());
                    locationBean3.setStorageName("H" + String.format("%04d", fourIndex));
                    locationBean3.setStorageCode("M" + fourIndex);
                    locationBean3.setLocationNo(locationBean2.getLocationNo() + "-" + locationBean3.getStorageName());
                    locationBean3.setLocationDesc(locationBean3.getStorageCode());
                    locationBean3.setStorageType(locationBean.getStorageType());
                    locationBean3.setLevel(LimsConstant.LEVEL_FORTH);
                    fourIndex++;
                    locationList.add(locationBean3);
                }
            }
        }
        getDao().insert(locationList);
        return locationBean.getId();
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.DELETE)
    @ValidateDataWith(LimsLocationDeleteValidator.class)
    public void delete(RestJsonWrapperBean wrapper) {
        List<LimsLocationBean> locationBeanList = wrapper.parse(LimsLocationBean.class);
        getDao().deleteBy(locationBeanList);
    }

    @Transactional
    @Override
    @ValidateDataWith(LimsLocationDeleteValidator.class)
    public void deleteByGroup(String group) {
        getDao().deleteByGroup(group);
    }

    @Override
    public List<LocationDTO> selectTree(MapperParameter parameter) {
        String parentId = ObjectUtils.toString(parameter.get("parentId"));
        if ("{parentId}".equals(parentId)) {
            parameter.put("parentId", null);
        }
        List<LimsLocationBean> orgList = new ArrayList<>();
        ArrayList<Future<List<LimsLocationBean>>> futures = new ArrayList<>();
        int count = getDao().selectTreeNodeCount(parameter);
        if (count < QUERY_MAX_QUANTITY) {
            orgList = getDao().selectTreeNodeList(parameter);
        } else {
            int num = count/QUERY_TIMES;
            for (int i = 0; i < QUERY_TIMES; i++) {
                try {
                    // 创建调度任务
                    int finalI = i;
                    FutureTask<List<LimsLocationBean>> futureTask = new FutureTask<>(() -> {
                        Map<String, Integer> map = new HashMap<>();
                        map.put("first", finalI *num);
                        if (finalI < QUERY_TIMES-1) {
                            map.put("second", num);
                        } else {
                            map.put("second", count-(finalI *num));
                        }
                        MapperParameter mapperParameter = new MapperParameter(parameter);
                        mapperParameter.put("limit", map);
                        return getDao().selectTreeNodeList(mapperParameter);
                    });
                    fixedThreadPool.submit(futureTask);
                    futures.add(futureTask);
                    // 执行任务
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            while(futures.size() > 0) {
                Iterator<Future<List<LimsLocationBean>>> iterator = futures.iterator();
                while (iterator.hasNext()) {
                    Future<List<LimsLocationBean>> future = iterator.next();
                    try {
                        // 判断是否返回结果，防止直接获取结果阻塞
                        if (future.isDone()) {
                            List<LimsLocationBean> locationList = future.get();
                            if (!locationList.isEmpty()) {
                                orgList.addAll(locationList);
                            }
                            iterator.remove();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }

            // 排序
            orgList.sort((o1, o2) -> {
                if (o1.getLevel().compareTo(o2.getLevel()) == 0) {
                    return o1.getSorter()-o2.getSorter();
                }
                return o1.getLevel().compareTo(o2.getLevel());
            });
        }

        List<LimsLocationBean> childOrgList = new ArrayList<>();
        // 过滤出全部的子节点
        if ("1".equals(parentId) || "{parentId}".equals(parentId)) {
            childOrgList.addAll(orgList);
        } else {
            this.treeChildList(childOrgList, orgList, Long.valueOf(parentId));
        }
        TreeDescriptor<LimsLocationBean> descriptor = new TreeDescriptor<>("id", "locationDesc");
        descriptor.setParseTreeNodeParentIdFunc(t -> String.valueOf(t.getParentId()));
        List<LocationDTO> treeList = LimsTreeHelper.parseTreeNode(childOrgList, descriptor, LocationDTO.class);
        treeList.sort(Comparator.comparing(LocationDTO::getSorter));
        TreeHelper.updateChildQty(treeList);
        return treeList;
    }

    public void treeChildList(List<LimsLocationBean> childOrgList, List<LimsLocationBean> locationList, Long parentId) {
        for (LimsLocationBean bean : locationList) {
            // 遍历出父id等于参数的id，add进子节点集合
            if (bean.getParentId().longValue() == parentId.longValue()) {
                // 递归遍历下一级
                childOrgList.add(bean);
                treeChildList(childOrgList, locationList, bean.getId());
            }
        }
    }

    @Transactional
    @Override
    public void saveBoards(RestJsonWrapperBean wrapperBean) {
        List<LimsLocationBoardBean> boardBeans = wrapperBean.parse(LimsLocationBoardBean.class);
        boardService.getDao().update(boardBeans, "locationId", "locationNo");
        CompletableFuture.runAsync(() -> {
            for (LimsLocationBoardBean locationBoardBean : boardBeans) {
                if ("1".equals(wrapperBean.getParamValue("action"))){
                    String[] locationNo = locationBoardBean.getLocationNo().split("-");
                    getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]), "1");
                    getDao().updateColorFlag(locationBoardBean.getLocationNo(), "1");
                }else{
                    updateParentColorFlag(locationBoardBean);
                    String[] locationNo = locationBoardBean.getLocationNo().split("-");
                    getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]),"1");
                    getDao().updateColorFlag(locationBoardBean.getLocationNo(),"1");
                    updateParentColorFlag(locationBoardBean);
                }
            }
        });
    }

    @Transactional
    @Override
    public void removeBoards(RestJsonWrapperBean wrapperBean) {
        List<LimsLocationBoardBean> boardBeans = wrapperBean.parse(LimsLocationBoardBean.class);
        boardBeans.forEach(b -> {
            b.setLocationId(null);
            b.setLocationNo(null);
        });
        boardService.getDao().update(boardBeans, "locationId", "locationNo");
        for (LimsLocationBoardBean locationBoardBean : boardBeans) {
            updateParentColorFlag(locationBoardBean);
        }
    }

    @Override
    public Boolean appendLocations(RestJsonWrapperBean wrapper) {
        LimsLocationBean locationBean = wrapper.parseUnique(LimsLocationBean.class);
        final Boolean[] flag = {true};
        // 加锁，防止同时添加，序号重复
        GikamConcurrentLocker.blockRun(LIMS_LOCATION_ID + ":" + locationBean.getId(), new Runnable() {
            @Override
            @Transactional
            public void run() {
                int sorter = Integer.parseInt(getDao().selectMaxSorterByParam(new MapperParameter(){{setFilter(SearchFilter.instance().match("level",LimsConstant.LEVEL_SECEND).filter(MatchPattern.EQ)
                        .match("storage",locationBean.getStorage()).filter(MatchPattern.EQ)
                        .match("parentId",locationBean.getId()).filter(MatchPattern.EQ));}}));
                switch (locationBean.getLevel()) {
                    case LimsConstant.LEVEL_FIRST:
                        appendCsForLocation(locationBean, sorter);
                        break;
                    case LimsConstant.LEVEL_SECEND:
                        appendJzsForLocation(locationBean, sorter);
                        break;
                    case LimsConstant.LEVEL_THIRD:
                        appendHzsForLocation(locationBean, sorter);
                        break;
                    default:
                        flag[0] = false;
                        break;
                }
            }
        });
        return flag[0];
    }

    private boolean isNotNull(String str){
        if (StringUtils.isBlank(str)){
            return false;
        }
        if (str.equalsIgnoreCase("null")){
            return false;
        }
        return true;
    }

    /**
     * 冰箱上加层
     * @param locationBean
     */
    private void appendCsForLocation(LimsLocationBean locationBean, int sorter) {
        List<LimsLocationBean> locationlist = new ArrayList<>();
        int cs = !StringUtils.isEmpty(locationBean.getExt$().get(LimsConstant.CS))?NumberUtils.parseInt(locationBean.getExt$().get(LimsConstant.CS)):0;// 层数
        int jzs = !StringUtils.isEmpty(locationBean.getExt$().get(LimsConstant.JZS))?NumberUtils.parseInt(locationBean.getExt$().get(LimsConstant.JZS)):0;// 架子数
        int hzs = !StringUtils.isEmpty(locationBean.getExt$().get(LimsConstant.HZS))?NumberUtils.parseInt(locationBean.getExt$().get(LimsConstant.HZS)):0;// 盒子数
        int locationSize = cs + cs * jzs + cs * jzs * hzs;
        List<Long> locationIdList = ApplicationContextHelper.getNextIdentityList(locationSize);
        int index = 0;
        // 层
//        String thirdNextCode = getDao().selectNextLayer("3");
//        int thirdCode = StringUtils.isEmpty(thirdNextCode) ? 1 : Integer.parseInt(thirdNextCode) + 1;
//
//        String fourNextCode = getDao().selectNextLayer("4");
//        int fourCode = StringUtils.isEmpty(fourNextCode) ? 1 : Integer.parseInt(fourNextCode) + 1;

        String secondNextCode = getDao().selectNextLayer("2",locationBean.getGroup());
        int secondCode = isNotNull(secondNextCode) ? 1 : Integer.parseInt(secondNextCode) + 1;
        // 层
        String thirdNextCode = getDao().selectNextLayer("3",locationBean.getGroup());
        int thirdCode = isNotNull(thirdNextCode) ? 1 : Integer.parseInt(thirdNextCode) + 1;

        String fourNextCode = getDao().selectNextLayer("4",locationBean.getGroup());
        int fourCode = isNotNull(fourNextCode) ? 1 : Integer.parseInt(fourNextCode) + 1;

        int thirdIndex = 1;
        int fourIndex = 1;
        for (int c = 1; c <= cs; c++) {
            LimsLocationBean lsilocationbeancs = new LimsLocationBean();
            lsilocationbeancs.setId(locationIdList.get(index++));
            lsilocationbeancs.setStorage(locationBean.getStorage());
            lsilocationbeancs.setStorageType(locationBean.getStorageType());
            lsilocationbeancs.setStorageCode("F" + c);

            //            lsilocationbeancs.setSorter(c + sorter -1);
            lsilocationbeancs.setStorageCode("F" + (c+secondCode-1));

            lsilocationbeancs.setLevel(LimsConstant.LEVEL_SECEND);
            lsilocationbeancs.setLayerCode(lsilocationbeancs.getId().toString());
            lsilocationbeancs.setParentId(locationBean.getId());
            lsilocationbeancs.setGroup(String.valueOf(locationBean.getId()));
            if ("液氮罐".equals(locationBean.getStorageType())){
                lsilocationbeancs.setStorageName("Q" + String.format("%04d", lsilocationbeancs.getSorter()));
            }else{
                lsilocationbeancs.setStorageName("J" + String.format("%04d", lsilocationbeancs.getSorter()));
            }
            lsilocationbeancs.setLocationNo(locationBean.getLocationNo() + "-" + lsilocationbeancs.getStorageName());
            lsilocationbeancs.setLocationDesc(lsilocationbeancs.getStorageCode());
            locationlist.add(lsilocationbeancs);
            // 架子
            for (int j = 1; j <= jzs; j++) {
                LimsLocationBean locationBean2 = new LimsLocationBean();
                locationBean2.setId(locationIdList.get(index++));
                locationBean2.setStorage(locationBean.getStorage());
                locationBean2.setParentId(lsilocationbeancs.getId());
                locationBean2.setGroup(String.valueOf(locationBean.getId()));
                locationBean2.setLayerCode(lsilocationbeancs.getLayerCode());
                locationBean2.setStorageName("T" + String.format("%04d", thirdCode + thirdIndex - 1));
                locationBean2.setLocationNo(lsilocationbeancs.getLocationNo() + "-" + locationBean2.getStorageName());

                //                locationBean2.setStorageCode("J" + j);
                locationBean2.setStorageCode("J" + (thirdCode + thirdIndex - 1));

                locationBean2.setLocationDesc(locationBean2.getStorageCode());
                locationBean2.setStorageType(locationBean.getStorageType());
                locationBean2.setColumnNum(1);
                locationBean2.setRowNum(j);
                locationBean2.setColNum(1);
                locationBean2.setSorter(j);
                locationBean2.setLevel(LimsConstant.LEVEL_THIRD);
                thirdIndex++;
                locationlist.add(locationBean2);
                // 盒子
                for (int k = 1; k <= hzs; k++) {
                    LimsLocationBean locationBean3 = new LimsLocationBean();
                    locationBean3.setId(locationIdList.get(index++));
                    locationBean3.setParentId(locationBean2.getId());
                    locationBean3.setGroup(String.valueOf(locationBean.getId()));
                    locationBean3.setSorter(k);
                    locationBean3.setStorage(locationBean.getStorage());

//                    locationBean3.setStorageName("H" + String.format("%04d", fourCode + fourIndex));
                    locationBean3.setStorageName("H" + String.format("%04d", fourCode + fourIndex-1));

                    locationBean3.setLocationNo(locationBean2.getLocationNo() + "-" + locationBean3.getStorageName());

//                    locationBean3.setStorageCode("M" + fourIndex);
                    locationBean3.setStorageCode("M" + (fourCode + fourIndex-1));

                    locationBean3.setLocationDesc(locationBean3.getStorageCode());
                    locationBean3.setStorageType(locationBean.getStorageType());
                    locationBean3.setLevel(LimsConstant.LEVEL_FORTH);
                    fourIndex++;
                    locationlist.add(locationBean3);
                }
            }
        }
        getDao().insert(locationlist);
    }

    /**
     * 层上加架子
     * @param locationBean
     */
    private void appendJzsForLocation(LimsLocationBean locationBean, int sorter) {
        List<LimsLocationBean> locationlist = new ArrayList<>();
        int jzs = !StringUtils.isEmpty(locationBean.getExt$().get(LimsConstant.JZS))?NumberUtils.parseInt(locationBean.getExt$().get(LimsConstant.JZS)):0;// 架子数
        int hzs = !StringUtils.isEmpty(locationBean.getExt$().get(LimsConstant.HZS))?NumberUtils.parseInt(locationBean.getExt$().get(LimsConstant.HZS)):0;// 盒子数
        int locationSize = jzs + jzs * hzs;
        List<Long> locationIdList = ApplicationContextHelper.getNextIdentityList(locationSize);
        int index = 0;
        int fourIndex = 1;
//        String thirdNextCode = getDao().selectNextLayer("3");
//        int thirdCode = StringUtils.isEmpty(thirdNextCode) ? 1 : Integer.parseInt(thirdNextCode) + 1;
//
//        String fourNextCode = getDao().selectNextLayer("4");
//        int fourCode = StringUtils.isEmpty(fourNextCode) ? 1 : Integer.parseInt(fourNextCode) + 1;

        String thirdNextCode = getDao().selectNextLayer("3",locationBean.getGroup());
        int thirdCode = isNotNull(thirdNextCode) ? 1 : Integer.parseInt(thirdNextCode) + 1;

        String fourNextCode = getDao().selectNextLayer("4",locationBean.getGroup());
        int fourCode = isNotNull(fourNextCode) ? 1 : Integer.parseInt(fourNextCode) + 1;

        // 架子
        for (int j = 1; j <= jzs; j++) {
            LimsLocationBean locationBean2 = new LimsLocationBean();
            locationBean2.setId(locationIdList.get(index++));
            locationBean2.setParentId(locationBean.getId());
            locationBean2.setLayerCode(locationBean.getLayerCode());

//            locationBean2.setStorageName("T" + String.format("%04d",thirdCode + j));
            locationBean2.setStorageName("T" + String.format("%04d",(thirdCode + j-1)));

            locationBean2.setColNum(1);
            locationBean2.setColumnNum(1);
            locationBean2.setStorage(locationBean.getStorage());
            locationBean2.setGroup(locationBean.getGroup());
            locationBean2.setLocationNo(locationBean.getLocationNo() + "-" + locationBean2.getStorageName());

//            locationBean2.setLocationDesc("J"+j);
            locationBean2.setLocationDesc("J"+(thirdCode + j-1));

            locationBean2.setStorageCode(locationBean2.getLocationDesc());
            locationBean2.setStorageType(locationBean.getStorageType());
            locationBean2.setLevel(LimsConstant.LEVEL_THIRD);
            locationBean2.setSorter(j+sorter-1);
            locationBean2.setRowNum(locationBean2.getSorter());
            locationlist.add(locationBean2);
            // 盒子
            for (int k = 1; k <= hzs; k++) {
                LimsLocationBean locationBean3 = new LimsLocationBean();
                locationBean3.setId(locationIdList.get(index++));
                locationBean3.setStorage(locationBean.getStorage());

//                locationBean3.setStorageCode("M" + fourIndex);
                locationBean3.setStorageCode("M" + (fourIndex + fourCode -1));

                locationBean3.setStorageName("H" + String.format("%04d",fourIndex + fourCode -1));
                locationBean3.setParentId(locationBean2.getId());
                locationBean3.setGroup(locationBean.getGroup());
                locationBean3.setSorter(k);
                locationBean3.setLocationNo(locationBean2.getLocationNo() + "-" + locationBean3.getStorageName());
                locationBean3.setLocationDesc(locationBean3.getStorageCode());
                locationBean3.setStorageType(locationBean.getStorageType());
                locationBean3.setLevel(LimsConstant.LEVEL_FORTH);
                fourIndex++;
                locationlist.add(locationBean3);
            }
        }
        getDao().insert(locationlist);
    }

    /**
     * 架子上加盒子
     * @param locationBean
     */
    private void appendHzsForLocation(LimsLocationBean locationBean, int sorter) {
        List<LimsLocationBean> locationlist = new ArrayList<>();
        int hzs = !StringUtils.isEmpty(locationBean.getExt$().get(LimsConstant.HZS))?NumberUtils.parseInt(locationBean.getExt$().get(LimsConstant.HZS)):0;// 盒子数
        int locationSize = hzs;
        List<Long> locationIdList = ApplicationContextHelper.getNextIdentityList(locationSize);
        int index = 0;
//        String fourNextCode = getDao().selectNextLayer("4");
//        int fourCode = StringUtils.isEmpty(fourNextCode) ? 1 : Integer.parseInt(fourNextCode) + 1;

        String fourNextCode = getDao().selectNextLayer("4",locationBean.getGroup());
        int fourCode = isNotNull(fourNextCode) ? 1 : Integer.parseInt(fourNextCode) + 1;

        // 盒子
        for (int k = 1; k <= hzs; k++) {
            LimsLocationBean locationBean3 = new LimsLocationBean();
            locationBean3.setId(locationIdList.get(index++));
            locationBean3.setParentId(locationBean.getId());
            locationBean3.setGroup(locationBean.getGroup());
            locationBean3.setSorter(k+sorter);
            locationBean3.setStorage(locationBean.getStorage());
            locationBean3.setStorageName("H" + String.format("%04d",fourCode + k -1));

//            locationBean3.setStorageCode("M" + fourCode);
            locationBean3.setStorageCode("M" + (fourCode + k -1));

            locationBean3.setLocationNo(locationBean.getLocationNo() + "-" + locationBean3.getStorageName());
            locationBean3.setLocationDesc(locationBean3.getStorageCode());
            locationBean3.setStorageType(locationBean.getStorageType());
            locationBean3.setLevel(LimsConstant.LEVEL_FORTH);
            locationlist.add(locationBean3);
        }
        getDao().insert(locationlist);
    }

    @Override
    @Transactional
    public Long insertStorage(LimsLocationBean locationBean) {
        locationBean.setId(ApplicationContextHelper.getNextIdentity());
        locationBean.setLevel(LimsConstant.LEVEL_FIRST);
        locationBean.setGroup(locationBean.getId().toString());
        int sorter = 1;
        if ("液氮罐".equals(locationBean.getStorageType())){
            List<LimsLocationBean> locationBeans = selectListByFilter(SearchFilter.instance().match("storage", locationBean.getStorage()).filter(MatchPattern.EQ)
                    .match("storageType", Arrays.asList("冰箱", "液氮罐")).filter(MatchPattern.OR).match("level",LimsConstant.LEVEL_FIRST).filter(MatchPattern.EQ));
            sorter = locationBeans.size() + 1;
            locationBean.setLocationNo(ApplicationContextHelper.getNextSequence("KSH.LIMS.LOCATION.LOCATIONNO","Y"));
        }else{
            sorter = Integer.parseInt(getDao().selectMaxSorterByParam(new MapperParameter(){{setFilter(SearchFilter.instance().match("level",LimsConstant.LEVEL_FIRST).filter(MatchPattern.EQ)
                    .match("storage",locationBean.getStorage()).filter(MatchPattern.EQ)
                    .match("storageType","冰箱").filter(MatchPattern.EQ));}}));
            locationBean.setLocationNo(ApplicationContextHelper.getNextSequence("KSH.LIMS.LOCATION.LOCATIONNO","B"));
            // 更新所有液氮罐后移
            updateYDG(locationBean);
        }
        locationBean.setSorter(sorter);
        locationBean.setStorageName(locationBean.getLocationNo());
        locationBean.setParentId(1L);
        locationBean.setLocationDesc(locationBean.getStorageCode());
        getDao().insert(locationBean);
        return locationBean.getId();
    }

    private void updateYDG(LimsLocationBean locationBean) {
        // 更新所有液氮罐后移
        LimsLocationBean condition = new LimsLocationBean();
        condition.setStorage(locationBean.getStorage());
        condition.setStorageType("液氮罐");
        List<LimsLocationBean> ydgUpdateBeans = getDao().selectList(condition, Arrays.asList("storageType", "storage"), Arrays.asList("id", "sorter"));
        if (!ydgUpdateBeans.isEmpty()){
            ydgUpdateBeans.forEach(y -> y.setSorter(y.getSorter() + 1));
            getDao().update(ydgUpdateBeans,"sorter");
        }
    }

    @Override
    @Transactional
    public LimsLocationBean saveLayer(LimsLocationBean layer) {
        if (ObjectUtils.isEmpty(layer)){
            throw new InvalidDataException(I18nHelper.getMessage("KSH.BX.ARGUMENTS.CANNOT.BE.EMPTY"));
        }

        // 查询上级desc
        List<LimsLocationBean> firstSecondLocations = getDao().selectListByIds(ArrayUtils.asList(layer.getParentId(),layer.getId()));
        Map<Long, List<LimsLocationBean>> listMap = firstSecondLocations.stream().collect(Collectors.groupingBy(LimsLocationBean::getId));
        LimsLocationBean firstLocationBean = listMap.get(layer.getParentId()).get(0);
        LimsLocationBean secondLocationBean = listMap.get(layer.getId()).get(0);
        if (!secondLocationBean.getStorageCode().equals(layer.getStorageCode())){
            secondLocationBean.setStorageCode(layer.getStorageCode());
            // 上层描述 + 层名称
            secondLocationBean.setLocationDesc(firstLocationBean.getLocationDesc() + "-" + layer.getStorageCode());
            getDao().update(secondLocationBean,"storageCode","locationDesc");
        }
        // 层
        List<LimsLocationBean> locationBeans = selectListByFilter(SearchFilter.instance().match("parentId", layer.getId()).filter(MatchPattern.EQ)
                .match("level", LimsConstant.LEVEL_THIRD).filter(MatchPattern.EQ));
        if (locationBeans.isEmpty()) return null;

        List<ChildLayerDTO> childLayers = layer.getChildLayers();
        List<LimsLocationBean> insertList = new ArrayList<>();
        List<LimsLocationBean> updateList = new ArrayList<>();
        List<Long> ids = locationBeans.stream().map(LimsLocationBean::getId).collect(Collectors.toList());
        for (int i = 0; i < childLayers.size(); i++){ // 列

            ChildLayerDTO childLayer = childLayers.get(i);

            for (int j = 0; j < childLayer.getChildren().size(); j++){ // 行

                ChildDTO child = childLayer.getChildren().get(j);

                // 刪除
                if (!ObjectUtils.isEmpty(child.getId()) && ids.contains(child.getId())){
                    ids.remove(child.getId());
                }
                // 保存
                Optional<LimsLocationBean> first = locationBeans.stream().filter(t -> !ObjectUtils.isEmpty(child.getId()) && StringUtils.equals(child.getId().toString(), t.getId().toString())).findFirst();
                if (first.isPresent()){
                    LimsLocationBean locationBean = first.get();
                    if (!StringUtils.equals(locationBean.getStorageCode(),child.getStorageCode())){
                        locationBean.setStorageCode(child.getStorageCode());
                        locationBean.setLocationDesc(secondLocationBean.getLocationDesc() + "-" + child.getStorageCode());
                        locationBean.setSorter(child.getSorter());
                        locationBean.setRowNum(childLayer.getRowNum());
                        updateList.add(locationBean);
                        continue;
                    }
                }
                // 新增
                if (ObjectUtils.isEmpty(child.getId())){

                    LimsLocationBean element = new LimsLocationBean();
                    element.setId(ApplicationContextHelper.getNextIdentity());
                    element.setStorageType(layer.getStorageType());
                    element.setStorage(layer.getStorage());
                    element.setParentId(layer.getId());
                    element.setRowNum(childLayer.getRowNum());
                    element.setColumnNum(layer.getColumnNum());
                    element.setColNum(childLayer.getColNum());
                    element.setSorter(Integer.parseInt("3" + childLayer.getColNum() + child.getSorter()));
                    element.setLayerCode(layer.getLayerCode());
                    element.setStorageName(ApplicationContextHelper.getNextSequence("KSH.LIMS.LOCATION.LOCATIONNO","T"));
                    element.setStorageCode(child.getStorageCode());
                    element.setLevel(LimsConstant.LEVEL_THIRD);
                    element.setGroup(layer.getGroup());
                    element.setLocationNo(secondLocationBean.getLocationNo() + "-" +element.getStorageName());
                    element.setLocationDesc(secondLocationBean.getLocationDesc() + "-" + child.getStorageCode());
                    insertList.add(element);
                }
            }
        }

        if (!ids.isEmpty()){
            List<LimsLocationBean> fourList = selectListByFilter(SearchFilter.instance().match("parentId", ids).filter(MatchPattern.OR));
            if (!fourList.isEmpty()){
                List<LimsLocationBoardBean> boardBeans = boardService.getDao().selectListByOneColumnValues(fourList.stream().map(LimsLocationBean::getId).collect(Collectors.toList()), "locationId", Arrays.asList("id"));
                if (!boardBeans.isEmpty()) {
                    throw new InvalidDataException(I18nHelper.getMessage("KSH.BX.PLEASE.REMOVE.THE.PLATE.FIRST"));
                }else{ // 删除盒子
                    getDao().deleteBy(fourList,"parentId");
                }
            }
            getDao().deleteByIdList(ids);
        }

        if (!updateList.isEmpty()){
            getDao().update(updateList,"storageCode","locationDesc","sorter","rowNum");
        }

        if (!insertList.isEmpty()){
            getDao().insert(insertList);
        }

        updateSecondLevelDesc(Arrays.asList(secondLocationBean));

        return layer;
    }

    @Override
    @Transactional
    public Long addLayer(LimsLocationBean locationBean) {
        if (ObjectUtils.isEmpty(locationBean)){
            throw new InvalidDataException(I18nHelper.getMessage("KSH.BX.ARGUMENTS.CANNOT.BE.EMPTY"));
        }
        List<LimsLocationBean> insertLocationList = new ArrayList<>();
        List<ChildLayerDTO> childLayers = locationBean.getChildLayers();
        // 获取父级描述
        LimsLocationBean firstLocationBean =  getDao().selectById(locationBean.getParentId());
        //添加层
        int sorter = Integer.parseInt(getDao().selectMaxSorterByParam(new MapperParameter(){{setFilter(SearchFilter.instance().match("level",LimsConstant.LEVEL_SECEND).filter(MatchPattern.EQ)
                .match("storage",locationBean.getStorage()).filter(MatchPattern.EQ)
                .match("storageType",locationBean.getStorageType()).filter(MatchPattern.EQ)
                .match("parentId",locationBean.getParentId()).filter(MatchPattern.EQ));}}));
        LimsLocationBean parentLocationBean = new LimsLocationBean();
        parentLocationBean.setId(ApplicationContextHelper.getNextIdentity());
        parentLocationBean.setStorage(locationBean.getStorage());
        parentLocationBean.setStorageType(locationBean.getStorageType());
        parentLocationBean.setStorageCode(locationBean.getStorageCode());

        parentLocationBean.setSorter(sorter);
        parentLocationBean.setLevel(LimsConstant.LEVEL_SECEND);
        parentLocationBean.setLayerCode(parentLocationBean.getId().toString());
        if ("液氮罐".equals(locationBean.getStorageType())){
            parentLocationBean.setStorageName(ApplicationContextHelper.getNextSequence("KSH.LIMS.LOCATION.LOCATIONNO","Q"));
        }else{
            parentLocationBean.setStorageName(ApplicationContextHelper.getNextSequence("KSH.LIMS.LOCATION.LOCATIONNO","J"));
        }
        parentLocationBean.setGroup(locationBean.getGroup());
        parentLocationBean.setParentId(locationBean.getParentId());
        parentLocationBean.setLocationNo(locationBean.getLocationNo() + "-" + parentLocationBean.getStorageName());
        parentLocationBean.setLocationDesc(firstLocationBean.getLocationDesc() + "-" + parentLocationBean.getStorageCode());
        insertLocationList.add(parentLocationBean);

        int columnNum = locationBean.getColumnNum(); //总列数
        int rowNum = childLayers.stream().mapToInt(ChildLayerDTO::getRowNum).sum(); // 总行数
        List<Long> ids = ApplicationContextHelper.getNextIdentityList(columnNum * rowNum);
        for (int i = 0; i<childLayers.size(); i++){ // 列

            ChildLayerDTO childLayer = childLayers.get(i);

            for (int j = 0; j < childLayer.getChildren().size(); j++){ // 行

                ChildDTO child = childLayer.getChildren().get(j);
                LimsLocationBean element = new LimsLocationBean();
                element.setId(ids.remove(0));
                element.setStorageType(locationBean.getStorageType());
                element.setStorage(locationBean.getStorage());
                element.setParentId(parentLocationBean.getId());
                element.setRowNum(childLayer.getChildren().size());
                element.setColumnNum(columnNum);

                element.setColNum(childLayer.getColNum());
                element.setSorter(Integer.parseInt("3" + childLayer.getColNum() + child.getSorter()));
                element.setStorageCode(child.getStorageCode());
                element.setStorageName(ApplicationContextHelper.getNextSequence("KSH.LIMS.LOCATION.LOCATIONNO","T"));
                element.setLocationNo(parentLocationBean.getLocationNo() + "-" + element.getStorageName());
                element.setLevel(LimsConstant.LEVEL_THIRD);
                element.setLayerCode(parentLocationBean.getLayerCode());
                element.setGroup(locationBean.getGroup());
                element.setLocationDesc(parentLocationBean.getLocationDesc() + "-" + child.getStorageCode());
                insertLocationList.add(element);
            }
        }
        getDao().insert(insertLocationList);
        return insertLocationList.get(0).getId();
    }


    @Override
    public List<LimsLocationBean> editStorage(LimsLocationBean layer) {

        if (ObjectUtils.isEmpty(layer)) return CollectionUtils.emptyList();
        List<LimsLocationBean> results = selectListByFilter(SearchFilter.instance().match("group",layer.getGroup()).filter(MatchPattern.EQ)
                .match("level",ArrayUtils.asList("2","3")).filter(MatchPattern.OR));
        Map<String, List<LimsLocationBean>> listMap = results.stream().collect(Collectors.groupingBy(LimsLocationBean::getLayerCode));
        List<LimsLocationBean> targetList = new ArrayList<>();
        listMap.keySet().forEach(key -> {

            List<LimsLocationBean> locationBeans = listMap.get(key);// 整层

            LimsLocationBean secondBean = locationBeans.stream().filter(locationBean -> locationBean.getLevel().equals(LimsConstant.LEVEL_SECEND)).findFirst().get();
            LimsLocationBean entity = new LimsLocationBean();
            entity.setId(secondBean.getId());
            entity.setParentId(secondBean.getParentId());
            entity.setLevel(secondBean.getLevel());
            entity.setGroup(secondBean.getGroup());
            entity.setSorter(secondBean.getSorter());

            entity.setStorage(secondBean.getStorage());
            entity.setStorageType(secondBean.getStorageType());
            entity.setStorageName(secondBean.getStorageName());
            entity.setLayerCode(secondBean.getLayerCode());
            entity.setStorageCode(secondBean.getStorageCode());
            List<LimsLocationBean> thirdBeanList = locationBeans.stream().filter(locationBean -> locationBean.getLevel().equals(LimsConstant.LEVEL_THIRD)).collect(Collectors.toList());
            entity.setColumnNum(thirdBeanList.get(0).getColumnNum());

            Map<Integer, List<LimsLocationBean>> childLayerMapList = thirdBeanList.stream().collect(Collectors.groupingBy(LimsLocationBean::getColNum));
            List<ChildLayerDTO> targetChildLayerList = new ArrayList<>();
            childLayerMapList.keySet().forEach(childKey -> {

                List<LimsLocationBean> childLayers = childLayerMapList.get(childKey);
                LimsLocationBean locationBean = childLayers.get(0);
                ChildLayerDTO childLayer = new ChildLayerDTO();
                childLayer.setColNum(locationBean.getColNum());
                childLayer.setRowNum(locationBean.getRowNum());

                List<ChildDTO> targetChildrenList = new ArrayList<>();
                childLayers.sort(Comparator.comparing(LimsLocationBean::getSorter));

                childLayers.forEach(cd -> {
                    ChildDTO child = new ChildDTO();
                    child.setId(cd.getId());
                    child.setStatus(cd.getStatus());
                    child.setStorageName(cd.getStorageName());
                    child.setStorageCode(cd.getStorageCode());
                    child.setStorage(cd.getStorage());
                    child.setColor(cd.getColor());
                    child.setStorageType(cd.getStorageType());
                    child.setLocationNo(cd.getLocationNo());
                    child.setLocationDesc(cd.getLocationDesc());
                    child.setSorter(cd.getSorter());
                    targetChildrenList.add(child);
                });

                childLayer.setChildren(targetChildrenList);

                targetChildLayerList.add(childLayer);
            });

            entity.setChildLayers(targetChildLayerList);

            targetList.add(entity);
        });
        targetList.sort(Comparator.comparing(LimsLocationBean::getSorter));
        return targetList;
    }

    @Override
    @Transactional
    public JSONObject delStorage(LimsLocationBean storageLocationBean) {
        JSONObject json = new JSONObject();
        json.put("flag","0");
        List<LimsLocationBean> locationBeans = selectListByFilter(SearchFilter.instance()
                .match("group", storageLocationBean.getGroup()).filter(MatchPattern.EQ));

        if (locationBeans.stream().noneMatch(f -> StringUtils.equals(f.getLevel(),LimsConstant.LEVEL_FORTH))){
            delLocation(locationBeans,storageLocationBean);
        } else{
            List<LimsLocationBean> fourLocationBeans = locationBeans.stream().filter(f -> StringUtils.equals(f.getLevel(), LimsConstant.LEVEL_FORTH)).collect(Collectors.toList());
            List<Long> ids = fourLocationBeans.stream().map(LimsLocationBean::getId).collect(Collectors.toList());
            List<LimsLocationBoardBean> boardBeans = boardService.getDao().selectListByOneColumnValues(ids, "locationId", ArrayUtils.asList("id","locationId"));
            if (boardBeans.isEmpty()){
                delLocation(locationBeans,storageLocationBean);
            }else{
                List<Long> locationIds = boardBeans.stream().map(LimsLocationBoardBean::getLocationId).collect(Collectors.toList());
                if (LimsConstant.LEVEL_FORTH.equals(storageLocationBean.getLevel())){
                    if (locationIds.contains(storageLocationBean.getId())){
                        json.put("flag","1");
                        json.put("msg",I18nHelper.getMessage("KSH.BX.PLAESE.REMOVE.THE.PLATE.UNDER.THE.FROZEN.BOX.FIRST"));
                    }else{
                        getDao().delete(storageLocationBean.getId());
                    }
                }else if (LimsConstant.LEVEL_SECEND.equals(storageLocationBean.getLevel())){
                    List<LimsLocationBean> fourHaveBoardList = fourLocationBeans.stream().filter(four -> locationIds.contains(four.getId())).collect(Collectors.toList());
                    List<Long> thirdIds = fourHaveBoardList.stream().map(LimsLocationBean::getParentId).distinct().collect(Collectors.toList());
                    if (locationBeans.stream().anyMatch(f -> thirdIds.contains(f.getId()))){
                        List<Long> secondIds = locationBeans.stream().filter(f -> thirdIds.contains(f.getId())).map(LimsLocationBean::getParentId).distinct().collect(Collectors.toList());
                        if (secondIds.contains(storageLocationBean.getId())){
                            json.put("flag","1");
                            json.put("msg",I18nHelper.getMessage("KSH.BX.PLEASE.REMOVE.THE.PLATE.UNDER.THE.LAYER.FIRST"));
                        }else{
                            delLocation(locationBeans,storageLocationBean);
                        }
                    }
                }else if (LimsConstant.LEVEL_FIRST.equals(storageLocationBean.getLevel())){
                    json.put("flag","1");
                    json.put("msg",I18nHelper.getMessage("KSH.BX.PLEASE.REMOVE.THE.PLATE.UNDER.THE.REFRIGERATOR.FIRST"));
                }
            }
        }

        return json;
    }

    @Override
    public JSONObject delLayerChild(Long id) {
        JSONObject json = new JSONObject();
        json.put("flag","0");
        if (ObjectUtils.isEmpty(id)){
            return json;
        }
        // 校验是否有板子
        List<LimsLocationBean> locationBeans = selectListByFilter(SearchFilter.instance().match("parentId", id).filter(MatchPattern.EQ));
        List<Long> ids = locationBeans.stream().map(LimsLocationBean::getId).collect(Collectors.toList());
        List<LimsLocationBoardBean> boardBeans = boardService.getDao().selectListByOneColumnValues(ids, "locationId", ArrayUtils.asList("id","locationId"));
        if (!boardBeans.isEmpty()) {
            json.put("flag", "1");
            json.put("msg", I18nHelper.getMessage("KSH.BX.PLEASE.REMOVE.THE.PLATE.UNDER.THE.LAYER.FIRST"));
        }
        return json;
    }

    @Transactional
    public void delLocation(List<LimsLocationBean> locationBeans, LimsLocationBean storageLocationBean) {
        if (LimsConstant.LEVEL_FIRST.equals(storageLocationBean.getLevel())){
            getDao().deleteBy(locationBeans,"group");
        }else if (LimsConstant.LEVEL_SECEND.equals(storageLocationBean.getLevel())){
            if (locationBeans.stream().anyMatch(ff -> LimsConstant.LEVEL_THIRD.equals(ff.getLevel())
                    && storageLocationBean.getId().equals(ff.getParentId()))){
                List<LimsLocationBean> locationBeanList = locationBeans.stream().filter(ff -> LimsConstant.LEVEL_THIRD.equals(ff.getLevel())
                        && storageLocationBean.getId().equals(ff.getParentId())).collect(Collectors.toList());
                getDao().deleteBy(locationBeanList,"parentId");
                List<Long> thirdIds = locationBeanList.stream().map(LimsLocationBean::getId).collect(Collectors.toList());
                if (locationBeans.stream().anyMatch(fff -> LimsConstant.LEVEL_FORTH.equals(fff.getLevel()) && thirdIds.contains(fff.getParentId()))){
                    List<LimsLocationBean> storageLocationBeans = locationBeans.stream().filter(fff -> LimsConstant.LEVEL_FORTH.equals(fff.getLevel()) && thirdIds.contains(fff.getParentId())).collect(Collectors.toList());
                    getDao().deleteBy(storageLocationBeans,"parentId");
                }
            }
            getDao().delete(storageLocationBean.getId());
        }else if (LimsConstant.LEVEL_FORTH.equals(storageLocationBean.getLevel())){
            getDao().delete(storageLocationBean.getId());
        }
    }

    @Override
    @Transactional
    public Long addBox(List<LimsLocationBean> locationBeans) {

        if (CollectionUtils.isEmpty(locationBeans)) return -1L;
        LimsLocationBean thirdLocationBean = getDao().selectById(locationBeans.get(0).getParentId());
        List<String> storageCodes = locationBeans.stream().map(LimsLocationBean::getStorageCode).distinct().collect(Collectors.toList());
        if (storageCodes.size() != locationBeans.size()){
            throw new InvalidDataException(I18nHelper.getMessage("core.validator.column.not-unique"));
        }
        List<Long> ids = ApplicationContextHelper.getNextIdentityList(locationBeans.size());
        List<LimsLocationBean> insertLocationBeans = new ArrayList<>();
        AtomicInteger sorter = new AtomicInteger(Integer.parseInt(getDao().selectMaxSorterByParam(new MapperParameter() {{
            setFilter(SearchFilter.instance().match("parentId", locationBeans.get(0).getParentId()).filter(MatchPattern.EQ));
        }})));
        for (LimsLocationBean location : locationBeans){
            LimsLocationBean entity = new LimsLocationBean();
            entity.setId(ids.remove(0));
            entity.setLevel(LimsConstant.LEVEL_FORTH);
            entity.setGroup(location.getGroup());
            entity.setStorage(location.getStorage());
            entity.setStorageType(location.getStorageType());
            entity.setParentId(location.getParentId());
            entity.setSorter(sorter.getAndIncrement());
            entity.setStorageName(ApplicationContextHelper.getNextSequence("KSH.LIMS.LOCATION.LOCATIONNO","H"));
            entity.setLocationNo(location.getLocationNo() + "-" + entity.getStorageName());
            entity.setLocationDesc(thirdLocationBean.getLocationDesc() + "-" + location.getStorageCode());
            entity.setStorageCode(location.getStorageCode());
            insertLocationBeans.add(entity);
        }

        getDao().insert(insertLocationBeans);

        return insertLocationBeans.get(0).getId();
    }

    @Override
    public List<LocationDTO> selectTree(LimsLocationBean storageLocationBean) {
        MapperParameter temp = new MapperParameter();
        temp.setFilter(SearchFilter.instance().match("createdByOrgId",LocalContextHelper.getLoginOrgId()).filter(MatchPattern.EQ));
        Long parentId = storageLocationBean.getParentId();
        if (!ObjectUtils.isEmpty(storageLocationBean.getParentId()) && StringUtils.equals("1",storageLocationBean.getParentId().toString())){
            temp.put("parentId","1");
        }else if (!ObjectUtils.isEmpty(storageLocationBean.getParentId())){
            temp.setFilter(SearchFilter.instance().match("parentId",storageLocationBean.getParentId()).filter(MatchPattern.EQ));
        }
        if (!ObjectUtils.isEmpty(storageLocationBean.getStorage())){
            temp.setFilter(SearchFilter.instance().match("storage",storageLocationBean.getStorage()).filter(MatchPattern.EQ));
        }
        List<LimsLocationBean> orgList = new ArrayList<>();
        ArrayList<Future<List<LimsLocationBean>>> futures = new ArrayList<>();
        int count = getDao().selectTreeNodeCount(temp);
        if (count < QUERY_MAX_QUANTITY) {
            orgList = getDao().selectTreeNodeList(temp);
        } else {
            int num = count/QUERY_TIMES;
            for (int i = 0; i < QUERY_TIMES; i++) {
                try {
                    // 创建调度任务
                    int finalI = i;
                    FutureTask<List<LimsLocationBean>> futureTask = new FutureTask<>(() -> {
                        Map<String, Integer> map = new HashMap<>();
                        map.put("first", finalI *num);
                        if (finalI < QUERY_TIMES-1) {
                            map.put("second", num);
                        } else {
                            map.put("second", count-(finalI *num));
                        }
                        MapperParameter mapperParameter = new MapperParameter(temp);
                        mapperParameter.put("limit", map);
                        return getDao().selectTreeNodeList(mapperParameter);
                    });
                    fixedThreadPool.submit(futureTask);
                    futures.add(futureTask);
                    // 执行任务
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            while(futures.size() > 0) {
                Iterator<Future<List<LimsLocationBean>>> iterator = futures.iterator();
                while (iterator.hasNext()) {
                    Future<List<LimsLocationBean>> future = iterator.next();
                    try {
                        // 判断是否返回结果，防止直接获取结果阻塞
                        if (future.isDone()) {
                            List<LimsLocationBean> locationList = future.get();
                            if (!locationList.isEmpty()) {
                                orgList.addAll(locationList);
                            }
                            iterator.remove();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }

            // 排序
            orgList.sort((o1, o2) -> {
                if (o1.getLevel().compareTo(o2.getLevel()) == 0) {
                    return o1.getSorter()-o2.getSorter();
                }
                return o1.getLevel().compareTo(o2.getLevel());
            });
        }

        List<LimsLocationBean> childOrgList = new ArrayList<>();
        // 过滤出全部的子节点
        if ("1".equals(parentId) || "{parentId}".equals(parentId)) {
            childOrgList.addAll(orgList);
        } else {
            this.treeChildList(childOrgList, orgList, Long.valueOf(parentId));
        }
        TreeDescriptor<LimsLocationBean> descriptor = new TreeDescriptor<>("id", "locationDesc");
        descriptor.setParseTreeNodeParentIdFunc(t -> String.valueOf(t.getParentId()));
        List<LocationDTO> treeList = LimsTreeHelper.parseTreeNode(childOrgList, descriptor, LocationDTO.class);
        treeList.sort(Comparator.comparing(LocationDTO::getSorter));
        TreeHelper.updateChildQty(treeList);
        return treeList;
    }

    @Override
    public List<Map<String,Object>> staticData(String codeCategoryId) {
        List<Map<String,Object>> mapList = getDao().staticData(codeCategoryId);
        if (mapList.isEmpty()) return Collections.emptyList();
        return mapList;
    }

    @Override
    public List<LimsLocationBean> queriesStorage(LimsLocationBean locationBean) {
        locationBean.setCreatedByOrgId(LocalContextHelper.getLoginOrgId());
        return selectList(locationBean,Order.asc("storageType"), Order.asc("sorter"));
    }

    @Override
    @Transactional
    public void saveBoards(LimsLocationBoardBean locationBoardBean) {
        String[] locationNo = locationBoardBean.getLocationNo().split("-");
        boardService.getDao().update(locationBoardBean, "locationId", "locationNo");
        // 校验盒子下板子是否全部占满
        List<LimsLocationBoardBean> locationBoardBeans = boardService.getDao().selectListByOneColumnValue(locationBoardBean.getLocationId(), "locationId");
        List<Long> boardIds = locationBoardBeans.stream().map(LimsLocationBoardBean::getId).collect(Collectors.toList());
        List<LimsLocationBoardHoleBean> boardHoleBeans = locationBoardHoleService.getDao().selectListByOneColumnValues(boardIds, "boardId");
        String layLocationNo = locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]);

        if (boardHoleBeans.stream().allMatch(all -> !ObjectUtils.isEmpty(all.getSampleId()))) {
            getDao().updateColorFlag(locationBoardBean.getLocationNo(), "2");
            // 层下板子是否全部占满
            List<LimsLocationBoardBean> boardBeans = boardService.selectListByFilter(SearchFilter.instance().match("locationNo", layLocationNo).filter(MatchPattern.SB));
            List<Long> ids = boardBeans.stream().map(LimsLocationBoardBean::getId).collect(Collectors.toList());
            List<LimsLocationBoardHoleBean> holeBeans = locationBoardHoleService.getDao().selectListByOneColumnValues(ids, "boardId");
            if (holeBeans.stream().allMatch(all -> !ObjectUtils.isEmpty(all.getSampleId()))) {
                getDao().updateColorFlag(layLocationNo, "2");
            } else {
                getDao().updateColorFlag(layLocationNo, "1");
            }
        } else {
            getDao().updateColorFlag(layLocationNo, "1");
            getDao().updateColorFlag(locationBoardBean.getLocationNo(), "1");
        }
    }

    @Override
    @Transactional
    public void removeBoards(LimsLocationBoardBean locationBoardBean) {
        locationBoardBean.setLocationId(null);
        locationBoardBean.setLocationNo(null);
        boardService.getDao().update(locationBoardBean,"locationNo","locationId");
        updateParentColorFlag(locationBoardBean);
    }

    @Transactional
    public void updateParentColorFlag(LimsLocationBoardBean locationBoardBean) {
        String boardLocationNo = locationBoardBean.getBoardLocationNo();
        String[] locationNo = boardLocationNo.split("-");
        List<LimsLocationBoardBean> boardBeans = boardService.selectListByFilter(SearchFilter.instance().match("locationNo", locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2])).filter(MatchPattern.SB));

        if (boardBeans.isEmpty()) {// 层下无板子
            getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]), "0");
            getDao().updateColorFlag(boardLocationNo, "0");
        } else {
            // 层下所有板子
            List<Long> boardIds = boardBeans.stream().map(LimsLocationBoardBean::getId).collect(Collectors.toList());
            List<LimsLocationBoardHoleBean> holeBeans = locationBoardHoleService.getDao().selectListByOneColumnValues(boardIds, "boardId");

            if (boardBeans.stream().noneMatch(f -> f.getLocationNo().equals(boardLocationNo))) {
                getDao().updateColorFlag(boardLocationNo, "0"); // 盒子下无板子
                if (holeBeans.stream().allMatch(all -> !ObjectUtils.isEmpty(all.getSampleId()))) {// 层下有板子都占满
                    getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]), "2");
                } else {
                    getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]), "1");
                }
            } else {
                // 盒子下所有板孔信息
                List<LimsLocationBoardBean> locationBoardBeans = boardBeans.stream().filter(f -> f.getLocationNo().equals(boardLocationNo)).collect(Collectors.toList());
                List<Long> boxBoardIds = locationBoardBeans.stream().map(LimsLocationBoardBean::getId).collect(Collectors.toList());
                List<LimsLocationBoardHoleBean> boardHoleBeans = holeBeans.stream().filter(t -> boxBoardIds.contains(t.getBoardId())).collect(Collectors.toList());
                if (boardHoleBeans.stream().allMatch(all -> !ObjectUtils.isEmpty(all.getSampleId()))) {
                    getDao().updateColorFlag(boardLocationNo, "2");
                    if (holeBeans.stream().allMatch(all -> !ObjectUtils.isEmpty(all.getSampleId()))) {// 层下有板子都占满
                        getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]), "2");
                    } else {
                        getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]), "1");
                    }
                } else {
                    getDao().updateColorFlag(boardLocationNo, "1");
                    getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]), "1");
                }
            }
        }
    }

    @Override
    @Transactional
    public void moveBoard(LimsLocationBoardBean locationBoardBean) {
        boardService.getDao().update(locationBoardBean, "locationNo", "locationId");
        locationBoardBean.setBoardLocationNo(locationBoardBean.getLocationNo());
        updateParentColorFlag(locationBoardBean);
    }

    @Override
    @Transactional
    public LimsLocationBean save(Long id, LimsLocationBean locationBean) {
        locationBean.setLocationDesc(locationBean.getStorageCode());
        getDao().updateIfChanged(locationBean);
        List<LimsLocationBean> secondLocationBeans = getDao().selectListByOneColumnValue(locationBean.getId(), "parentId");
        if (!secondLocationBeans.isEmpty()){
            secondLocationBeans.forEach(v -> v.setLocationDesc(locationBean.getLocationDesc() + "-" + v.getStorageCode()));
            getDao().update(secondLocationBeans,"locationDesc");
            updateSecondLevelDesc(secondLocationBeans);
        }
        return locationBean;
    }

    @Override
    @Transactional
    public LimsLocationBean editBox(LimsLocationBean locationBean) {
        LimsLocationBean boxBean = selectById(locationBean.getId());
        LimsLocationBean parentBean = getDao().selectById(boxBean.getParentId());
        locationBean.setLocationDesc(parentBean.getLocationDesc() + "-" + locationBean.getStorageCode());
        getDao().updateIfChanged(locationBean);
        return locationBean;
    }

    @Override
    public List<LimsLocationBoardBean> selectBoardList() {
        List<Map<String,Object>> mapList = getDao().selectBoardList();
        if (mapList.isEmpty()) return CollectionUtils.emptyList();
        return mapList.stream().map(m-> PersistableHelper.mapToPersistable(m,LimsLocationBoardBean.class)).collect(Collectors.toList());
    }

    @Override
    public JSONObject validatorCode(LimsLocationBean locationBean) {
        JSONObject json = new JSONObject();
        List<LimsLocationBean> locationBeans = selectList(locationBean);
        json.put("flag",true);
        if (locationBeans.isEmpty()) return json;
        json.put("flag",false);
        json.put("msg",I18nHelper.getMessage("core.validator.column.not-unique"));
        return json;
    }

    @Override
    public JSONObject selectI18Message(){
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("locale", LocaleContextHolder.getLocale());
        jsonObject.put("columnSettings",I18nHelper.getMessage("KSH.BX.COLUMN.SETTINGS"));
        jsonObject.put("nameEmpty",I18nHelper.getMessage("KSH.BX.COLUMN.NAME.EMPTY"));
        jsonObject.put("columnEmpty",I18nHelper.getMessage("KSH.BX.COLUMN.EMPTY"));
        jsonObject.put("rowNameEmpty",I18nHelper.getMessage("KSH.BX.ROW.NAME.EMPTY"));
        jsonObject.put("firstColumnData",I18nHelper.getMessage("KSH.BX.PLEASE.SELECT.COLUMN.DATA.FIRST"));
        jsonObject.put("lessZero",I18nHelper.getMessage("KSH.BX.COLUMN.LESS.ZERO"));
        jsonObject.put("editSuccess",I18nHelper.getMessage("KSH.BX.COLUMN.EDIT.SUCCESS"));
        jsonObject.put("noAvailablePlate",I18nHelper.getMessage("KSH.BX.CARRIER.BOARD.AVAILABLE"));
        jsonObject.put("firstBoardCode",I18nHelper.getMessage("KSH.BX.SELECT.BOARD.CODE.FIRST"));
        jsonObject.put("ableDeviceInfo",I18nHelper.getMessage("KSH.BX.NO.DEVICE.INFO.ABLE"));
        jsonObject.put("selectBoxMoved",I18nHelper.getMessage("KSH.BX.SELECT.BOX.MOVE.FIRST"));
        jsonObject.put("deleteDevice",I18nHelper.getMessage("KSH.BX.SURE.TO.DELETE.DEVICE"));
        jsonObject.put("deviceStorage",I18nHelper.getMessage("KSH.BX.SELECT.DEVICE.LIBRARY"));
        jsonObject.put("selectDeviceType",I18nHelper.getMessage("KSH.BX.SELECT.DEVICE.TYPE"));
        jsonObject.put("selectDeviceCode",I18nHelper.getMessage("KSH.BX.SELECT.DEVICE.CODE"));
        jsonObject.put("editFailed",I18nHelper.getMessage("KSH.BX.EDIT.FAILED"));
        jsonObject.put("addFailed",I18nHelper.getMessage("KSH.BX.ADD.FAILED"));
        jsonObject.put("deviceCode",I18nHelper.getMessage("KSH.BX.DEVICE.CODE"));
        jsonObject.put("cancel",I18nHelper.getMessage("KSH.BX.CANCEL"));
        jsonObject.put("confirm",I18nHelper.getMessage("KSH.BX.CONFIRM"));
        jsonObject.put("save",I18nHelper.getMessage("KSH.BX.SAVE"));
        jsonObject.put("addSuccess",I18nHelper.getMessage("KSH.BX.SUCCESSFULLY.ADDED"));
        jsonObject.put("addLayer",I18nHelper.getMessage("KSH.BX.ADDING.LAYERS"));
        jsonObject.put("name",I18nHelper.getMessage("KSH.BX.NAME"));
        jsonObject.put("colNum",I18nHelper.getMessage("KSH.BX.COLUMN.NUMBER"));
        jsonObject.put("rowNum",I18nHelper.getMessage("KSH.BX.ROW.NUMBER"));
        jsonObject.put("layerSettings",I18nHelper.getMessage("KSH.BX.LAYER.SETTINGS"));
        jsonObject.put("colData",I18nHelper.getMessage("KSH.BX.ADD.COLUMN.DATA.FIRST"));
        jsonObject.put("column",I18nHelper.getMessage("KSH.BX.COLUMN"));
        jsonObject.put("editLayer",I18nHelper.getMessage("KSH.BX.EDIT.LAYER"));
        jsonObject.put("delRow",I18nHelper.getMessage("KSH.BX.ARE.YOU.SURE.TO.DELETE.THE.CHANGE.LINE"));
        jsonObject.put("addBox",I18nHelper.getMessage("KSH.BX.ADD.FROZEN.BOX"));
        jsonObject.put("boxCode",I18nHelper.getMessage("KSH.BX.FROZEN.BOX.NUMBER"));
        jsonObject.put("addPlate",I18nHelper.getMessage("KSH.BX.ADD.BOARD"));
        jsonObject.put("plateCode",I18nHelper.getMessage("KSH.BX.PLATE.CODE"));
        jsonObject.put("movePlate",I18nHelper.getMessage("KSH.BX.MOVE.PLATE"));
        jsonObject.put("movingTo",I18nHelper.getMessage("KSH.BX.MOVING.TO"));
        jsonObject.put("movePlateSuccess",I18nHelper.getMessage("KSH.BX.MOVING.THE.PLATE.SUCCEDED"));
        jsonObject.put("editFrozenBox",I18nHelper.getMessage("KSH.BX.EDIT.FROZEN.BOX"));
        jsonObject.put("deleteBox",I18nHelper.getMessage("KSH.BX.ARE.YOU.TO.DALETE.BOX"));
        jsonObject.put("deleteLayer",I18nHelper.getMessage("KSH.BX.ARE.YOU.SURE.TO.DELETE.THIS.LAYER"));
        jsonObject.put("deletePlate",I18nHelper.getMessage("KSH.BX.ARE.YOU.SURE.TO.DALETE.PLATE"));
        jsonObject.put("deleteSuccess",I18nHelper.getMessage("KSH.BX.DALETE.SUCCESSFULLY"));
        jsonObject.put("movePlateFrozenBoxFirst",I18nHelper.getMessage("KSH.BX.PLAESE.REMOVE.THE.PLATE.UNDER.THE.FROZEN.BOX.FIRST"));
        jsonObject.put("movePlateLayerFirst",I18nHelper.getMessage("KSH.BX.PLEASE.REMOVE.THE.PLATE.UNDER.THE.LAYER.FIRST"));
        jsonObject.put("movePlateRefrigerator",I18nHelper.getMessage("KSH.BX.PLEASE.REMOVE.THE.PLATE.UNDER.THE.REFRIGERATOR.FIRST"));
        jsonObject.put("removePlateFirst",I18nHelper.getMessage("KSH.BX.PLEASE.REMOVE.THE.PLATE.FIRST"));
        jsonObject.put("details",I18nHelper.getMessage("KSH.BX.DETAILS"));
        jsonObject.put("locationNumber",I18nHelper.getMessage("KSH.BX.LOCATION.NUMBER"));
        jsonObject.put("editDevice",I18nHelper.getMessage("KSH.BX.EDIT.DEVICE"));
        jsonObject.put("sampleCode",I18nHelper.getMessage("KSH.BX.SAMPLE.CODE"));
        jsonObject.put("sampleType",I18nHelper.getMessage("KSH.BX.SAMPLE.TYPE"));
        jsonObject.put("addArea",I18nHelper.getMessage("KSH.BX.ADD.AREA"));
        jsonObject.put("inStoreDate",I18nHelper.getMessage("KSH.BX.DATE.OF.STORAGE"));
        jsonObject.put("areaSettings",I18nHelper.getMessage("KSH.BX.AREA.SETTINGS"));
        jsonObject.put("selectBoxData",I18nHelper.getMessage("KSH.BX.PLEASE.SELECT.THE.BOX.DATA.FIRST"));
        jsonObject.put("deleteArea",I18nHelper.getMessage("KSH.BX.ARE.YOU.SURE.WANT.TO.DALETE.THE.AREA"));
        jsonObject.put("selectFrozenBoxData",I18nHelper.getMessage("KSH.BX.PLEASE.SELECT.THE.FROZEN.SHELF.DATA.FIRST"));
        jsonObject.put("biorepository",I18nHelper.getMessage("KSH.BX.SAMPLE.STORAGE.MANAGER"));
        jsonObject.put("RefrigeratorStorage",I18nHelper.getMessage("KSH.BX.STORAGE"));
        jsonObject.put("addEquip",I18nHelper.getMessage("KSH.BX.ADD.EQUIP"));
        jsonObject.put("loadedBoard",I18nHelper.getMessage("KSH.BX.TIP.LOADED.ON.BOARD"));
        jsonObject.put("notLoadedBoard",I18nHelper.getMessage("KSH.BX.TIP.NOT.LOADED.ON.NOT.BOARD"));
        jsonObject.put("deviceLibrary",I18nHelper.getMessage("KSH.BX.DEVICE.LIBRARY"));
        jsonObject.put("deviceType",I18nHelper.getMessage("KSH.BX.DEVICE.TYPE"));
        jsonObject.put("inputFrozenBoxCode",I18nHelper.getMessage("KSH.BX.INPUT.FROZEN.CODE"));
        jsonObject.put("editArea",I18nHelper.getMessage("KSH.BX.EDIT.AREA"));
        return jsonObject;
    }

    @Override
    @Transactional
    public void updateSecondLevelDesc(List<LimsLocationBean> secondLocationBeans) {

        // 获取第二层下节点描述
        List<LimsLocationBean> thirdBeans = getDao().selectListByOneColumnValues(secondLocationBeans.stream().map(LimsLocationBean::getId).collect(Collectors.toList()), "parentId");

        if (!thirdBeans.isEmpty()){

            secondLocationBeans.forEach(sd -> thirdBeans.stream().filter(f -> sd.getId().equals(f.getParentId())).forEach(v -> v.setLocationDesc(sd.getLocationDesc() + "-" + v.getStorageCode())));
            getDao().update(thirdBeans,"locationDesc");

            List<LimsLocationBean> fourUpdateList = getDao().selectListByOneColumnValues(thirdBeans.stream().map(LimsLocationBean::getId).collect(Collectors.toList()),"parentId");
            if (!fourUpdateList.isEmpty()){
                thirdBeans.forEach(p -> fourUpdateList.stream().filter(c -> p.getId().equals(c.getParentId())).forEach(v -> v.setLocationDesc(p.getLocationDesc() + "-" + v.getStorageCode())));
                getDao().update(fourUpdateList,"locationDesc");
            }
        }
    }

    @Override
    @Transactional
    public Long addArea(List<LimsLocationBean> locationBeans) {
        if (CollectionUtils.isEmpty(locationBeans)) return -1L;
        List<String> storageCodes = locationBeans.stream().map(LimsLocationBean::getStorageCode).distinct().collect(Collectors.toList());
        if (storageCodes.size() != locationBeans.size()){
            throw new InvalidDataException(I18nHelper.getMessage("core.validator.column.not-unique"));
        }
        List<Long> ids = ApplicationContextHelper.getNextIdentityList(locationBeans.size());
        List<LimsLocationBean> insertLocationBeans = new ArrayList<>();
        AtomicInteger sorter = new AtomicInteger(Integer.parseInt(getDao().selectMaxSorterByParam(new MapperParameter() {{
            setFilter(SearchFilter.instance().match("parentId", locationBeans.get(0).getParentId()).filter(MatchPattern.EQ));
        }})));
        List<Long> parentIds = locationBeans.stream().map(LimsLocationBean::getParentId).distinct().collect(Collectors.toList());
        List<LimsLocationBean> fathers = this.selectListByIds(parentIds);
        for (LimsLocationBean location : locationBeans) {
            LimsLocationBean entity = new LimsLocationBean();
            entity.setId(ids.remove(0));
            entity.setLevel(LimsConstant.LEVEL_FIFTH);
            entity.setGroup(location.getGroup());
            entity.setStorage(location.getStorage());
            entity.setStorageType(location.getStorageType());
            entity.setParentId(location.getParentId());
            entity.setSorter(sorter.getAndIncrement());
            entity.setStorageName(ApplicationContextHelper.getNextSequence("KSH.LIMS.LOCATION.LOCATIONNO","L"));
            entity.setLocationNo(location.getLocationNo() + "-" + entity.getStorageName());
            entity.setLocationDesc(location.getLocationDesc() + "-" + location.getStorageCode());
            fathers.stream().filter(f -> f.getId().equals(location.getParentId())).findAny().ifPresent(f -> {
                entity.setLocationDesc(f.getLocationDesc() + "-" + location.getStorageCode());
            });
            entity.setStorageCode(location.getStorageCode());
            insertLocationBeans.add(entity);
        }

        getDao().insert(insertLocationBeans);

        return insertLocationBeans.get(0).getId();
    }

    @Override
    @Transactional
    public JSONObject newDelStorage(LimsLocationBean storageLocationBean) {
        JSONObject json = new JSONObject();
        json.put("flag","0");
        List<LimsLocationBean> locationBeans = selectListByFilter(SearchFilter.instance()
                .match("group", storageLocationBean.getGroup()).filter(MatchPattern.EQ));

        if (locationBeans.stream().noneMatch(f -> StringUtils.equals(f.getLevel(),LimsConstant.LEVEL_FIFTH))){
            delLocation(locationBeans,storageLocationBean);
        } else{
            List<LimsLocationBean> fifthLocationBeans = locationBeans.stream().filter(f -> StringUtils.equals(f.getLevel(), LimsConstant.LEVEL_FIFTH)).collect(Collectors.toList());
            List<Long> ids = fifthLocationBeans.stream().map(LimsLocationBean::getId).collect(Collectors.toList());
            List<LimsLocationBoardBean> boardBeans = boardService.getDao().selectListByOneColumnValues(ids, "locationId", ArrayUtils.asList("id","locationId"));
            if (boardBeans.isEmpty()){
                delLocation(locationBeans,storageLocationBean);
            }else{
                List<Long> locationIds = boardBeans.stream().map(LimsLocationBoardBean::getLocationId).collect(Collectors.toList());
                if (LimsConstant.LEVEL_FIFTH.equals(storageLocationBean.getLevel())){
                    if (locationIds.contains(storageLocationBean.getId())){
                        json.put("flag","1");
                        json.put("msg",I18nHelper.getMessage("KSH.BX.PLEASE.REMOVE.THE.PLATE.UNDER.THE.AREA.FIRST"));
                    }else{
                        getDao().delete(storageLocationBean.getId());
                    }
                }else if (LimsConstant.LEVEL_FORTH.equals(storageLocationBean.getLevel())){
                    List<LimsLocationBean> fifthHaveBoardList = fifthLocationBeans.stream().filter(four -> locationIds.contains(four.getId())).collect(Collectors.toList());
                    List<Long> fourIds = fifthHaveBoardList.stream().map(LimsLocationBean::getParentId).distinct().collect(Collectors.toList());
                    if (fourIds.contains(storageLocationBean.getId())){
                        json.put("flag","1");
                        json.put("msg",I18nHelper.getMessage("KSH.BX.PLAESE.REMOVE.THE.PLATE.UNDER.THE.FROZEN.BOX.FIRST"));
                    }else{
                        delLocation(locationBeans, storageLocationBean);
                    }
                }else if (LimsConstant.LEVEL_SECEND.equals(storageLocationBean.getLevel())){
                    List<LimsLocationBean> fifthHaveBoardList = fifthLocationBeans.stream().filter(four -> locationIds.contains(four.getId())).collect(Collectors.toList());
                    List<Long> fourIds = fifthHaveBoardList.stream().map(LimsLocationBean::getParentId).distinct().collect(Collectors.toList());
                    if (locationBeans.stream().anyMatch(f -> fourIds.contains(f.getId()))){
                        List<Long> thirdIds = locationBeans.stream().filter(f -> fourIds.contains(f.getId())).map(LimsLocationBean::getParentId).distinct().collect(Collectors.toList());
                        if (locationBeans.stream().anyMatch(f -> thirdIds.contains(f.getId()))){
                            List<Long> secondIds = locationBeans.stream().filter(f -> thirdIds.contains(f.getId())).map(LimsLocationBean::getParentId).distinct().collect(Collectors.toList());
                            if (secondIds.contains(storageLocationBean.getId())){
                                json.put("flag","1");
                                json.put("msg",I18nHelper.getMessage("KSH.BX.PLEASE.REMOVE.THE.PLATE.UNDER.THE.LAYER.FIRST"));
                            }else{
                                delLocation(locationBeans,storageLocationBean);
                            }
                        }
                    }
                }else if (LimsConstant.LEVEL_FIRST.equals(storageLocationBean.getLevel())){
                    json.put("flag","1");
                    json.put("msg",I18nHelper.getMessage("KSH.BX.PLEASE.REMOVE.THE.PLATE.UNDER.THE.REFRIGERATOR.FIRST"));
                }
            }
        }

        return json;
    }

    @Override
    @Transactional
    public void newSaveBoards(LimsLocationBoardBean locationBoardBean) {
        String[] locationNo = locationBoardBean.getLocationNo().split("-");
        getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]).concat("-").concat(locationNo[3]),"1");
        getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]),"1");
        getDao().updateColorFlag(locationBoardBean.getLocationNo(),"1");
        boardService.getDao().update(locationBoardBean,"locationId","locationNo");
    }

    @Override
    @Transactional
    public void newRemoveBoards(LimsLocationBoardBean locationBoardBean) {
        locationBoardBean.setLocationId(null);
        locationBoardBean.setLocationNo(null);
        boardService.getDao().update(locationBoardBean,"locationNo","locationId");
        newUpdateParentColorFlag(locationBoardBean);
    }

    @Transactional
    public void newUpdateParentColorFlag(LimsLocationBoardBean locationBoardBean){
        String boardLocationNo = locationBoardBean.getBoardLocationNo();
        String[] locationNo = boardLocationNo.split("-");
        List<LimsLocationBoardBean> boardBeans = boardService.selectListByFilter(SearchFilter.instance().match("locationNo", locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2])).filter(MatchPattern.SB));

        if (boardBeans.isEmpty()){// 层下无板子
            getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]).concat("-").concat(locationNo[3]),"0");
            getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]),"0");
            getDao().updateColorFlag(boardLocationNo,"0");
        }else{
            // 校验盒子下区是否有板子
            if (boardBeans.stream().noneMatch(f -> f.getLocationNo().equals(boardLocationNo))){
                getDao().updateColorFlag(boardLocationNo,"0");
            }
        }
    }

    @Override
    @Transactional
    public void newMoveBoard(LimsLocationBoardBean locationBoardBean) {
        boardService.getDao().update(locationBoardBean, "locationNo", "locationId");
        updateParentColorFlag(locationBoardBean);
        String[] locationNo = locationBoardBean.getLocationNo().split("-");
        getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]).concat("-").concat(locationNo[3]),"1");
        getDao().updateColorFlag(locationNo[0].concat("-").concat(locationNo[1]).concat("-").concat(locationNo[2]),"1");
        getDao().updateColorFlag(locationBoardBean.getLocationNo(),"1");
    }

    @Override
    @Transactional
    public void updateColorFlag(String locationNo, String color) {
        getDao().updateColorFlag(locationNo, color);
    }

    @Override
    public List<LimsLocationBean> newQueriesStorage(LimsLocationBean locationBean) {
        return selectListByFilter(SearchFilter.instance().match("parentId",locationBean.getParentId()).filter(MatchPattern.EQ));
    }

    @Override
    public List<Map<String, Object>> kshStorageSelectable() {
        return getDao().kshStorageSelectable();
    }

    @Override
    public JSONObject validatorAreaCode(LimsLocationBean locationBean) {
        JSONObject json = new JSONObject();
        List<LimsLocationBean> locationBeans = selectList(locationBean);
        json.put("flag",true);
        if (locationBeans.isEmpty()) return json;
        json.put("flag",false);
        json.put("msg",I18nHelper.getMessage("core.validator.column.not-unique"));
        return json;
    }

    @Override
    public List<LocationDTO> selectTreeData(MapperParameter temp) {
        return selectTree(temp);
    }
}
